package com.example.dictionary.service;

import com.example.dictionary.config.DictionaryProperties;
import com.example.dictionary.repository.DownloadTaskMapper;
import com.example.dictionary.util.DiskSpaceUtil;
import com.example.memento.model.DictionarySource;
import com.example.memento.model.DownloadTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 词典文件下载服务
 */
@Service
public class DictionaryDownloadService {
    
    private static final Logger log = LoggerFactory.getLogger(DictionaryDownloadService.class);
    
    private final DictionaryProperties properties;
    private final RestTemplate restTemplate;
    private final ExecutorService executorService;
    private final DownloadTaskMapper downloadTaskMapper;
    private final DownloadPathMappingService pathMappingService;
    private final Map<String, DownloadTask> downloadTasks = new ConcurrentHashMap<>();
    
    public DictionaryDownloadService(DictionaryProperties properties, 
                                    DownloadTaskMapper downloadTaskMapper,
                                    DownloadPathMappingService pathMappingService) {
        this.properties = properties;
        this.downloadTaskMapper = downloadTaskMapper;
        this.pathMappingService = pathMappingService;
        this.restTemplate = new RestTemplate();
        this.executorService = Executors.newFixedThreadPool(properties.getDownload().getMaxConcurrent());
    }
    
    /**
     * 下载所有启用的词典源
     */
    @Async
    public CompletableFuture<List<DownloadTask>> downloadAllEnabledSources() {
        List<CompletableFuture<DownloadTask>> futures = new ArrayList<>();
        
        for (DictionarySource source : properties.getSources()) {
            if (source.isEnabled()) {
                futures.add(downloadSource(source));
            }
        }
        
        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .thenApply(v -> futures.stream()
                        .map(CompletableFuture::join)
                        .toList());
    }
    
    /**
     * 下载指定词典源
     */
    @Async
    public CompletableFuture<DownloadTask> downloadSource(DictionarySource source) {
        String taskId = UUID.randomUUID().toString();
        DownloadTask task = DownloadTask.builder()
                .taskId(taskId)
                .sourceName(source.getName())
                .url(source.getDownloadUrl())
                .status(DownloadTask.TaskStatus.PENDING)
                .build();
        
        // 设置创建时间戳
        task.onCreate();
        
        // 保存到数据库
        downloadTaskMapper.insert(task);
        
        downloadTasks.put(taskId, task);
        
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 检查是否已有下载记录
                String resourceKey = pathMappingService.buildDictionarySourceResourceKey(
                        source.getName(), source.getDownloadUrl());
                Optional<String> existingPath = pathMappingService.getDownloadPath(resourceKey);
                
                Path localPath;
                if (existingPath.isPresent()) {
                    Path existingPathObj = Paths.get(existingPath.get());
                    if (Files.exists(existingPathObj)) {
                        log.info("发现已下载的资源，使用现有路径: {} -> {}", resourceKey, existingPath.get());
                        localPath = existingPathObj;
                        
                        // 更新任务状态
                        task.setStatus(DownloadTask.TaskStatus.COMPLETED);
                        task.setEndTime(LocalDateTime.now());
                        task.setLocalPath(localPath.toString());
                        task.onUpdate();
                        downloadTaskMapper.updateStatus(task.getTaskId(), DownloadTask.TaskStatus.COMPLETED);
                        
                        log.info("词典源使用已下载文件: {} -> {}", source.getName(), localPath);
                        return task;
                    } else {
                        log.warn("映射的路径不存在，将重新下载: {}", existingPath.get());
                        pathMappingService.removeMapping(resourceKey);
                    }
                }
                
                task.setStatus(DownloadTask.TaskStatus.DOWNLOADING);
                task.onUpdate();
                downloadTaskMapper.updateStatus(task.getTaskId(), DownloadTask.TaskStatus.DOWNLOADING);
                log.info("开始下载词典源: {}", source.getName());
                
                String fileName = generateFileName(source);
                // 从全局配置中选择保存路径（支持多个路径，用逗号分隔）
                Path basePath = selectDownloadPath(source);
                localPath = basePath.resolve(fileName);
                
                log.info("选择下载路径: {} (来自全局配置)", basePath);
                
                // 确保目录存在
                Files.createDirectories(localPath.getParent());
                
                // 下载文件
                downloadFile(source.getDownloadUrl(), localPath, task);
                
                task.setStatus(DownloadTask.TaskStatus.COMPLETED);
                task.setEndTime(LocalDateTime.now());
                task.setLocalPath(localPath.toString());
                task.onUpdate();
                downloadTaskMapper.updateStatus(task.getTaskId(), DownloadTask.TaskStatus.COMPLETED);
                
                // 保存映射关系（下载成功后才保存）
                pathMappingService.saveMapping(resourceKey, localPath.toString());
                
                log.info("词典源下载完成: {} -> {}", source.getName(), localPath);
                
            } catch (Exception e) {
                task.setStatus(DownloadTask.TaskStatus.FAILED);
                task.setErrorMessage(e.getMessage());
                task.setEndTime(LocalDateTime.now());
                task.onUpdate();
                downloadTaskMapper.updateError(task.getTaskId(), e.getMessage(), DownloadTask.TaskStatus.FAILED);
                log.error("词典源下载失败: {}", source.getName(), e);
            }
            
            return task;
        }, executorService);
    }
    
    /**
     * 下载文件到本地
     */
    private void downloadFile(String url, Path localPath, DownloadTask task) throws IOException {
        URL fileUrl = new URL(url);
        
        try (InputStream inputStream = fileUrl.openStream();
             FileOutputStream outputStream = new FileOutputStream(localPath.toFile())) {
            
            byte[] buffer = new byte[properties.getDownload().getChunkSize()];
            int bytesRead;
            long totalBytes = 0;
            
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                totalBytes += bytesRead;
                task.setDownloadedBytes(totalBytes);
                
                // 更新进度
                if (totalBytes % (1024 * 1024) == 0) { // 每1MB更新一次
                    log.debug("下载进度: {} / {} bytes", totalBytes, "unknown");
                }
            }
            
            task.setTotalBytes(totalBytes);
        }
    }
    
    /**
     * 生成文件名
     */
    private String generateFileName(DictionarySource source) {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String extension = getFileExtension(source.getFormat());
        return String.format("%s_%s.%s", source.getName().toLowerCase(), timestamp, extension);
    }
    
    /**
     * 根据格式获取文件扩展名
     */
    private String getFileExtension(String format) {
        return switch (format.toLowerCase()) {
            case "cedict" -> "txt";
            case "wordnet" -> "xml";
            case "json" -> "json";
            case "csv" -> "csv";
            default -> "txt";
        };
    }
    
    /**
     * 获取下载任务状态
     */
    public Optional<DownloadTask> getDownloadTask(String taskId) {
        return Optional.ofNullable(downloadTasks.get(taskId));
    }
    
    /**
     * 获取所有下载任务
     */
    public List<DownloadTask> getAllDownloadTasks() {
        return new ArrayList<>(downloadTasks.values());
    }
    
    /**
     * 检查文件是否存在
     */
    public boolean isFileDownloaded(String sourceName) {
        Path storagePath = Paths.get(properties.getStorage().getPath());
        if (!Files.exists(storagePath)) {
            return false;
        }
        
        try {
            return Files.list(storagePath)
                    .anyMatch(path -> path.getFileName().toString().startsWith(sourceName.toLowerCase()));
        } catch (IOException e) {
            log.error("检查文件是否存在时出错", e);
            return false;
        }
    }
    
    /**
     * 获取已下载的文件列表
     */
    public List<Path> getDownloadedFiles() {
        Path storagePath = Paths.get(properties.getStorage().getPath());
        if (!Files.exists(storagePath)) {
            return Collections.emptyList();
        }
        
        try {
            return Files.list(storagePath)
                    .filter(Files::isRegularFile)
                    .toList();
        } catch (IOException e) {
            log.error("获取已下载文件列表时出错", e);
            return Collections.emptyList();
        }
    }
    
    /**
     * 选择下载路径（从全局配置的多个路径中选择最佳的）
     * 支持多个路径用逗号分隔，下载时会检查每个路径的磁盘空间，随机选择有足够空间的路径
     * 
     * @param source 词典源配置（参数保留用于兼容性，但不使用其中的 save-path）
     * @return 选择的路径
     */
    private Path selectDownloadPath(DictionarySource source) {
        // 从全局配置中获取保存路径
        String savePath = properties.getDownload().getSavePath();
        
        // 如果全局配置中有多个路径（逗号分隔）
        if (savePath != null && !savePath.isEmpty() && savePath.contains(",")) {
            List<Path> paths = DiskSpaceUtil.parsePaths(savePath);
            if (!paths.isEmpty()) {
                Optional<Path> selectedPath = DiskSpaceUtil.selectPathWithSpace(paths);
                if (selectedPath.isPresent()) {
                    log.info("从全局配置的多个路径中选择: {} (可用路径: {})", 
                            selectedPath.get(), paths.size());
                    return selectedPath.get();
                }
            }
        }
        
        // 单个路径或默认路径
        if (savePath != null && !savePath.isEmpty()) {
            String singlePath = savePath.split(",")[0].trim();
            Path path = Paths.get(singlePath);
            log.info("使用全局配置的单个路径: {}", path);
            return path;
        }
        
        // 使用默认路径 data/res
        Path defaultPath = Paths.get("data/res");
        log.info("未配置全局保存路径，使用默认路径: {}", defaultPath);
        return defaultPath;
    }
}